package com.naza.rpc.Server;

import com.google.common.eventbus.EventBus;
import com.naza.rpc.async.RpcCallback;
import com.naza.rpc.consumer.balance.manage.ClientManage;
import com.naza.rpc.core.MessageCallBack;
import com.naza.rpc.event.ClientStopEventListener;
import com.naza.rpc.model.LoadBalance;
import com.naza.rpc.model.LoadBalanceImpl;
import com.naza.rpc.model.RpcRequest;
import com.naza.rpc.model.ServiceInstance;
import com.naza.rpc.netty.RpcServerLoader;
import com.naza.rpc.serialize.RpcSerializeProtocol;
import com.naza.rpc.netty.RpcSendExecutor;
import com.naza.rpc.netty.RpcSendHandler;
import com.naza.rpc.util.PropertiesUtil;

import java.util.UUID;

/**
 *  rpc client manually bootstrap
 *  @author yl
 */
public class ClientBootstrap {

    private EventBus eventBus = new EventBus();

    private ClientManage clientManage = ClientManage.INSTANCE;

    private RpcSendExecutor messageSendExecutor = RpcSendExecutor.getInstance();

    public ClientBootstrap (){
        ClientStopEventListener listener = new ClientStopEventListener();
        eventBus.register(listener);
    }

    public ClientBootstrap setAddressAndProtocol(String protocol){
        messageSendExecutor.setRpcServerLoader(RpcSerializeProtocol.valueOf(protocol));
        return this;
    }

    public RpcInvoker getInvoker(String interfaceName){
        clientManage.addService(interfaceName);
        clientManage.monitor(interfaceName);
        messageSendExecutor.startConnect(interfaceName);
        return new RpcInvoker(interfaceName);
    }

    public class RpcInvoker {

        private String interfaceName;

        public RpcInvoker(String interfaceName){
            this.interfaceName = interfaceName;
        }

        public void invokeAsync(String method,  Class<?>[] parameterTypes, Object[] args,final RpcCallback callback){
            final long start = System.currentTimeMillis();
            try {
                RpcRequest request = new RpcRequest();
                request.setMessageId(UUID.randomUUID().toString());
                request.setClassName(this.interfaceName);
                request.setMethodName(method);
                request.setTypeParameters(parameterTypes);
                request.setParametersVal(args);
                ServiceInstance provider = select();
                if(null != provider){
                    RpcSendHandler handler = RpcServerLoader.getInstance().getMessageSendHandler(provider.getIp()+":"+provider.getPort());
                    // 客户端将请求发向服务端，结果异步回调
                    MessageCallBack callBack = handler.sendRequest(request,callback);
                }
            } catch (Throwable e) {
                System.out.println(e);
            }
        }

        public Object invokeSync(String method,  Class<?>[] parameterTypes, Object[] args){
            final long start = System.currentTimeMillis();
            try {
                RpcRequest request = new RpcRequest();
                request.setMessageId(UUID.randomUUID().toString());
                request.setClassName(this.interfaceName);
                request.setMethodName(method);
                request.setTypeParameters(parameterTypes);
                request.setParametersVal(args);
                ServiceInstance provider = select();
                if(null == provider){
                    //还没有服务端
                    return null;
                }
                RpcSendHandler handler = RpcServerLoader.getInstance().getMessageSendHandler(provider.getIp()+":"+provider.getPort());
                // 客户端将请求发向服务端，结果异步回调
                MessageCallBack callBack = handler.sendRequest(request);
                return callBack.start();
            } catch (Throwable e) {
                System.out.println(e);
            }
            return null;
        }

        public Object getObject()  {
            // client端 接口实例的动态代理
            try {
                return messageSendExecutor.execute(getObjectType());
            } catch (Exception e) {
                e.printStackTrace();
            }
            return null;
        }

        public Class<?> getObjectType() {
            try {
                //classloader.loadclass不会进行链接，不做类的初始化(静态方法/代码块/静态对象);
                //class.forName 会进行类的初始化
                return this.getClass().getClassLoader().loadClass(interfaceName);
            } catch (ClassNotFoundException e) {
                System.err.println("can not load class:"+interfaceName + e);
            }
            return null;
        }

        //每次调用之前先根据负载均衡策略选择一个
        private ServiceInstance select(){
            ServiceInstance serviceInstance = clientManage.selectClient(interfaceName,
                    getLoadBalanceRoute(PropertiesUtil.getINSTANCE().getValue("loadbalanceRoute")));
            return serviceInstance;
        }

        private LoadBalance getLoadBalanceRoute(String route){
            if("round".equals(route)){
                return LoadBalanceImpl.DEFAULT;
            }
            else if("random".equals(route)){
                return new LoadBalanceImpl(LoadBalance.Type.ROUND_ROBIN);
            }
            return LoadBalanceImpl.DEFAULT;
        }
    }
}
